﻿<?php

/**
 * SixFramework 微型 PHP 框架
 *
 * @copyright   Copyright (c) 2014 
 * @author      Tony Lu <lucups@live.com> (http://mousika.cn/)
 * @license     GPL2.0
 * @version     0.0.3 beta
 */


/**
 * 类：
 * 1. 配置类：Conf
 * 2. 核心类：Sf
 * 3. 数据访问：Db
 * 4. 控制器：Controller
 * 5. 工具类：Utils
 */

/**
 * 项目配置类
 */
class Conf {

    // 数据库配置
    public static $DB = array(
        'host' => 'localhost', // 主机名
        'port' => '3306', // 端口
        'name' => 'sixframework', // 数据库名
        'user' => 'root', // 用户名
        'pass' => 'medeolinx', // 密码
    );

    // 路径配置
    public static $PATH = array(
        'm' => 'model/', // 模型（实体）目录
        'v' => 'view/', // 模板（视图）目录
        'c' => 'controller/', // 控制器目录
        'a' => 'asset/', // 存放资源（js,css,image）的目录
    );

    const STR_SALT = 'SixFramework'; // 密码盐
    const STR_INDEX = 'index.php'; // 项目首页

    const SUFFIX_CONTROLLER = 'Controller'; // 控制器后缀
    const SUFFIX_ACTION = 'Action'; // 控制器动作后缀

}

/**
 * 核心类
 * Class Sf (SixFramework)
 */
class Sf {

    /**
     * 入口函数，加载页面
     */
    public static function load($c = 'main', $a = 'index') {
        
        // 查找对应的控制器动作, c = controller, a = action
        if (isset($_GET['c'])) {
            $c = $_GET['c'];
        }
        if (isset($_GET['a'])) {
            $a = $_GET['a'];
        }
        
        // 引入对应的控制器
        $c = Utils::camelName($c) . Conf::SUFFIX_CONTROLLER;
        require(Conf::$PATH['c'] . $c . '.php');
        
        // 实例化控制器
        eval("\$cx = new $c();");
        
        // 执行相应的动作
        $a = Utils::camelName($a, Utils::CAMEL_STYLE_N) . Conf::SUFFIX_ACTION;
        echo $cx->$a();
    }

    /**
     * 路由
     */
    public static function router($c, $a, $param = null) {
        $r = Conf::STR_INDEX . '?c=' . $c . '&a=' . $a;
        if ($param == null) {
            return $r;
        }
        if (gettype($param == 'string')) {
            return $r . '&' . $param;
        }
        if (gettype($param) == 'array') {
            foreach ($param as $k => $v) {
                $r .= '&' . $k . '=' . $v;
            }
            return $r;
        }
        return $r;
    }

}

/**
 * 数据库操作类
 * Class Db
 */
class Db {

    private static $connection;
    public $table; // 表名
    public $pk; // 主键

    /**
     * 构造函数
     */
    public function __construct() {
        if(!self::$connection){
            self::$connection = $this->_connect();    
        }
    }

    /**
     * 创建数据库连接
     * @return resource|string
     */
    private function _connect() {
        $conn = mysql_pconnect(Conf::$DB['host'] . ':' . Conf::$DB['port'], Conf::$DB['user'], Conf::$DB['pass']);
        if (!$conn) {
            exit('Could not connect: ' . mysql_error());
        }
        mysql_select_db(Conf::$DB['name'], $conn);
        mysql_query('set names utf8');
        return $conn;
    }

    /**
     * 主要是识别 find 方法的变种
     * ===========================================
     * findAll(array): 查找所有数据。支持的参数：
     *      sort: 排序
     * Example:
     *      $m->findAll(array('sort'=>'user_id'));
     * ===========================================
     * findOneByXXX(int): 查找一条数据，如果结果有很多条，
     * 则返回第一条。
     * Example:
     *      $m->findOneByUserId($user_id);
     * ===========================================
     * @param $func
     * @param $args
     * @return string
     */
    public function __call($func, $args) {

        if (substr($func, 0, 4) == 'find') {
            $condition = '';
            if (substr($func, 4) == 'All') {
                return $this->find($condition);
            } else if (substr($func, 4, 5) == 'OneBy') {
                $filed = substr($func, 9);
                $filed = Utils::underScoreName($filed);
                $args0 = $args[0];
                $condition .= "WHERE $filed = $args0 ";
                $rs = $this->find($condition);
                if ($rs) {
                    return $rs[0];
                } else {
                    return $rs;
                }
            }
        } else if (substr($func, 0, 3) == 'get') {
            $property = Utils::underScoreName(substr($func, 3));
            if (isset($this->$property)) {
                return $this->$property;
            }
        } else if (substr($func, 0, 3) == 'set') {
            $property = Utils::underScoreName(substr($func, 3));
            $this->$property = $args[0];
        }
    }

    /**
     * find
     * @param $condition (sql)
     * @return array
     */
    public function find($condition) {
        $sql = "SELECT * FROM $this->table " . $condition;
        $rs = mysql_query($sql, self::$connection);
        if ($rs == null) {
            return null;
        }
        $data = array();
        while ($row = mysql_fetch_array($rs)) {
            $data[] = $row;
        }
        return $data;
    }

    public function save() {
        $sql = "INSERT INTO $this->table ";
        $str_filed = '(';
        $str_value = '(';
        foreach ($this->properties as $filed) {
            $filedx = Utils::camelName($filed);
            eval("\$value = \$this->get$filedx();");
            if (!is_null($value)) {
                $str_filed .= $filed . ',';
                if (is_numeric($value)) {
                    $str_value .= $value . ",";
                } else {
                    $str_value .= "'" . $value . "',";
                }
            }
        }
        $str_filed = substr($str_filed, 0, strlen($str_filed) - 1) . ')';
        $str_value = substr($str_value, 0, strlen($str_value) - 1) . ')';
        $sql .= $str_filed . ' VALUES ' . $str_value;
        return mysql_query($sql, self::$connection);
    }

    public function delete($id) {
        $sql = "DELETE FROM $this->table WHERE $this->pk = " . $id;
        return mysql_query($sql, self::$connection);
    }

    public function update($m) {
        $sql = "UPDATE $this->table SET ";
        foreach ($m as $key => $value) {
            if (is_numeric($key) or $key == $this->pk) {
                continue;
            }
            $sql .= $key . '=' . "'" . $value . "' ,";
        }
        $sql = substr($sql, 0, strlen($sql) - 1);
        $sql .= "WHERE $this->pk = " . $m[$this->pk];
        return mysql_query($sql, self::$connection);
    }

    /**
     * 析构函数
     */
    public function __destroy() {
        //mysql_close(self::$connection);
    }

}

/**
 * 控制器类
 * Class Controller
 */
class Controller {


    function __construct() {
    }

    public function getModel($model_name) {
        require Conf::$PATH['m'] . $model_name . '.php';
        //eval("\$m = new $model_name();");
        $m = new $model_name();
        return $m;
    }

    /**
     * 根据对应的控制器/动作加载对应的模板
     * @param $a
     * @param $data
     */
    public function getView($a, $data = null) {
        $c = get_class($this);
        if($data){
            foreach ($data as $k => $v) {
                eval("$$k = \$v;");
            } 
        }
        $c = str_replace(Conf::SUFFIX_CONTROLLER, '', $c);
        $a = str_replace(Conf::SUFFIX_ACTION, '', $a);
        require(Conf::$PATH['v'] . $c . '/' . $a . '.php');
    }

}

/**
 * 工具函数类
 * Class Utils
 */
class Utils {

    const CAMEL_STYLE_M = 0;
    const CAMEL_STYLE_N = 1;

    /**
     * 单向加密函数，加了很多很多盐~~
     * @param $str
     * @param string $salt
     * @return string
     */
    public static function encrypt($str, $salt = Conf::STR_SALT) {
        return md5(md5(md5($str . $salt) . $salt) . $salt);
    }

    /**
     * Rename File 文件重命名 以当前时间和随机码组成
     * @param $name
     * @param int $length
     * @return string
     */
    public static function rename($name, $length = 6) {
        $newName = self::timeStr() . '-' . self::getRandomCode($length);
        $tmp = strrchr($name, '.');
        if ($tmp != false) {
            $newName .= $tmp;
        }
        return $newName;
    }

    /**
     * 生成指定长度的随机码
     * @param int $n 需要的随机码长度
     * @return string
     */
    public static function getRandomCode($n = 32) {
        return substr(str_shuffle('abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, $n);
    }

    /**
     * 邮箱合法性判断
     * @param $email
     * @return boolean
     */
    public static function checkEmailValidity($email) {
        $pattern = "/([a-z0-9]*[-_.]?[a-z0-9]+)*@([a-z0-9]*[-_]?[a-z0-9]+)+[.][a-z]{2,3}([.][a-z]{2})?/i";
        return preg_match($pattern, $email);
    }

    /**
     * 10进制 转 16进制
     * @return mixed
     */
    public static function decToHex() {
        $dec = rand(0, 255);
        $hexStr = '0123456789ABCDEF';
        $low = abs($dec % 16);
        $high = abs(($dec - $low) / 16);
        $hex = (strlen($hexStr) > $high ? $hexStr[$high] : $hexStr[0]) +
            (strlen($hexStr) > $low ? $hexStr[$low] : $hexStr[10]);
        return $hex;
    }

    /**
     * 驼峰命名转下划线命名，如 GoYourHome => go_your_home
     * @param $str
     * @return string
     */
    public static function underScoreName($str) {
        $str[0] = strtolower($str[0]);
        $strx = '';
        for ($i = 0; $i < strlen($str); $i++) {
            $v = ord($str[$i]);
            if ($v >= 65 && $v <= 90) {
                $strx .= '_' . strtolower($str[$i]);
            } else {
                $strx .= $str[$i];
            }
        }
        return $strx;
    }

    /**
     * 下划线命名转驼峰命名，如 go_your_home => GoYourHome
     * 如需要首字母小写，即 go_your_home => goYourHome，则给第二个参数赋值为 CAMEL_STYLE_N
     * @param $str
     * @param $style
     * @return string
     */
    public static function camelName($str, $style = Utils::CAMEL_STYLE_M) {
        if ($style == Utils::CAMEL_STYLE_M) {
            $str[0] = strtoupper($str[0]);
        }
        $str_x = '';
        $flag = false;
        for ($i = 0; $i < strlen($str); $i++) {
            if ($flag) {
                $str_x .= strtoupper($str[$i]);
                $flag = false;
                continue;
            }
            if ($str[$i] == '_') {
                $flag = true;
            } else {
                $str_x .= $str[$i];
            }
        }
        return $str_x;
    }

}